#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbtypes.h"
#include "wbio.h"
#include "wblib.h"

#include "nvtfat.h"
#include "nuc900_reg.h"


#include "nuc900_gnand.h"
#include "nuc900_sic.h"



#define SYS_CLOCK			15000000
#define UART_BAUD_RATE		115200

#define TEST_PATH			"C:\\TEST"


NDRV_T _nandDiskDriver0 = 
{
	nandInit0,
	nandpread0,
	nandpwrite0,
	nand_is_page_dirty0,
	nand_is_valid_block0,
	nand_ioctl,
	nand_block_erase0,
	nand_chip_erase0,
	0
};



static INT  delete_files(INT distance)
{
	CHAR     	szAsciiName[32], suDirName[64], suFullName[128];
	FILE_FIND_T tFileInfo;
	CHAR		suSlash[] = { '\\', 0x00, 0x00, 0x00 };
	INT			file_idx, nStatus;

	memset((UINT8 *)&tFileInfo, 0, sizeof(tFileInfo));	

	strcpy(szAsciiName, TEST_PATH);
	fsAsciiToUnicode(szAsciiName, suDirName, 1);
	sysprintf("    start to delete files...\n");

	nStatus = fsFindFirst(suDirName, NULL, &tFileInfo);
	if (nStatus < 0)
		return nStatus;

	file_idx = 1;
	do 
	{
		if ((tFileInfo.suLongName[0] == '0') || (tFileInfo.suLongName[0] == '.'))
			continue;
		
		if ((file_idx % distance) == 0)
		{	
			fsUnicodeCopyStr(suFullName, suDirName);
			fsUnicodeStrCat(suFullName, suSlash);
			fsUnicodeStrCat(suFullName, tFileInfo.suLongName);
			sysprintf("    delete file: %s\n", fsDebugUniStr(suFullName));
			nStatus = fsDeleteFile(suFullName, NULL);
			if (nStatus < 0)
			{
				sysprintf("failed to delete file.\n");
				return nStatus;
			}
		}
		file_idx++;
	
	} while (!fsFindNext(&tFileInfo));
	
	fsFindClose(&tFileInfo);
	return 0;
}


static INT  Action_Compare(CHAR *suFileName1, CHAR *szAsciiName1, 
							CHAR *suFileName2, CHAR *szAsciiName2)
{
	INT		hFile1, hFile2;
	INT		i, nLen1, nLen2, nCount, nStatus1, nStatus2;
	UINT8	buffer1[8192], buffer2[8192];
	
	hFile1 = fsOpenFile(suFileName1, szAsciiName1, O_RDONLY);
	if (hFile1 < 0)
		return hFile1;
	
	hFile2 = fsOpenFile(suFileName2, szAsciiName2, O_RDONLY);
	if (hFile2 < 0)
		return hFile2;
	
	nCount = 0;
	while (1)
	{
		nStatus1 = fsReadFile(hFile1, buffer1, 8192, &nLen1);
		nStatus2 = fsReadFile(hFile2, buffer2, 8192, &nLen2);
		
		if ((nStatus1 == ERR_FILE_EOF) && (nStatus2 == ERR_FILE_EOF))
		{
			fsCloseFile(hFile1);
			fsCloseFile(hFile2);
			return 0;
		}
		
		if (nLen1 != nLen2)
			break;
			
		if (memcmp(buffer1, buffer2, nLen1))
			break;
		
		nCount+=8;
		
		sysprintf("    %d KB\r", nCount);
	}
	
	fsCloseFile(hFile1);
	fsCloseFile(hFile2);
	
	for (i = 0; i < nLen1; i++)
	{
		if (buffer1[i] != buffer2[i])
			break;
	} 
	
	sysprintf("\n\nS: %02x %02x %02x %02x %02x %02x %02x %02x\n", buffer1[i], buffer1[i+1], buffer1[i+2], buffer1[i+3], buffer1[i+4], buffer1[i+5], buffer1[i+6], buffer1[i+7]); 
	sysprintf("D: %02x %02x %02x %02x %02x %02x %02x %02x\n", buffer2[i], buffer2[i+1], buffer2[i+2], buffer2[i+3], buffer2[i+4], buffer2[i+5], buffer2[i+6], buffer2[i+7]); 
	
	return -1;
}


INT  create_pattern_file()
{
	CHAR     szAsciiName[32], suFileName[64];
	INT	 	 hFile;
	INT      nWriteLen, nTime0, nStatus = 0;
	UINT32   uKBCnt = 0;

	strcpy(szAsciiName, TEST_PATH);
	fsAsciiToUnicode(szAsciiName, suFileName, 1);
	sysprintf("    make directory:  %s\n", szAsciiName);
	fsMakeDirectory(suFileName, NULL);

	memset(szAsciiName, 0, sizeof(szAsciiName));
	sprintf(szAsciiName, "%s\\%d", TEST_PATH, 0);
	sysprintf("    create file:  %s\n", szAsciiName);
	fsAsciiToUnicode(szAsciiName, suFileName, 1);

	hFile = fsOpenFile(suFileName, szAsciiName, O_CREATE | O_TRUNC);
	if (hFile < 0)
		return hFile;
		
	nStatus = 0;
	nTime0 = sysGetTicks(TIMER0);

	while (1)
	{
		nStatus = fsWriteFile(hFile, (UINT8 *)0, 64*1024, &nWriteLen);
		if (nStatus < 0)
			break;
		
		uKBCnt += nWriteLen / 1024;
		
		if (uKBCnt >= 10*1024)
			break;
	}
	nTime0 = sysGetTicks(TIMER0) - nTime0;
	if (nTime0 == 0) nTime0 = 1;

	sysprintf("%d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);
	fsCloseFile(hFile);
	return nStatus;
}


INT  file_test(INT idx)
{
	CHAR     szSrcName[32], suSrcName[64];
	CHAR     szDstName[32], suDstName[64];
	INT      nStatus = 0;

	memset(szSrcName, 0, sizeof(szSrcName));
	sprintf(szSrcName, "%s\\%d", TEST_PATH, 0);
	memset(szDstName, 0, sizeof(szDstName));
	sprintf(szDstName, "%s\\%d", TEST_PATH, idx);

	sysprintf("    copy file:  %s\n", szDstName);
	fsAsciiToUnicode(szSrcName, suSrcName, 1);
	fsAsciiToUnicode(szDstName, suDstName, 1);
	
	nStatus = fsCopyFile(suSrcName, NULL, suDstName, NULL);
	if (nStatus == ERR_DISK_FULL)
		return nStatus;
	if (nStatus < 0)
	{
		sysprintf("file copy failed.\n");
		return nStatus;
	}

	sysprintf("    compare file:  %s\n", szDstName);
	nStatus = Action_Compare(suSrcName, NULL, suDstName, NULL);
	if (nStatus < 0)
	{
		sysprintf("file compare failed.\n");
		return nStatus;
	}
	
	return 0;
}


int main()
{
    WB_UART_T 	uart;
	WB_PLL_T 	sysClock;
	NDISK_T *	ptNDisk;
	PDISK_T		*pDiskList;
	INT			i, file_idx, status;

	/* CACHE_ON	*/
	sysInvalidCache();
	sysEnableCache(CACHE_WRITE_THROUGH);

	sysClock.pll0 = PLL_200MHZ;				//PLL0 output clock
	sysClock.pll1 = PLL_200MHZ;				//PLL1 output clock
	sysClock.cpu_src = CPU_FROM_PLL0;		//Select CPU clock source
	sysClock.ahb_clk = AHB_CPUCLK_1_2;		//Select AHB clock divider
	sysClock.apb_clk = APB_AHB_1_2;			//Select APB clock divider
	sysSetPLLConfig(&sysClock);				//Call system function call

	//outpw(REG_MFSEL, inpw(REG_MFSEL) | 0x100);
    uart.uiFreq = SYS_CLOCK;
    uart.uiBaudrate = UART_BAUD_RATE;
    uart.uiDataBits = WB_DATA_BITS_8;
    uart.uiStopBits = WB_STOP_BITS_1;
    uart.uiParity = WB_PARITY_NONE;
    uart.uiRxTriggerLevel = LEVEL_1_BYTE;
    sysInitializeUART(&uart);
	sysprintf("UART initialized\n");
	/*--- init timer ---*/
	sysSetTimerReferenceClock (TIMER0, SYS_CLOCK);
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);

	fsInitFileSystem();

	/* Initialize FMI */
	sicIoctl(0, 200000, 0, 0);
	sicOpen();

	ptNDisk = (NDISK_T *)malloc(sizeof(NDISK_T));
	if (ptNDisk == NULL)
		sysprintf("malloc error!!\n");
	
	sysprintf("GNAND Init %x\n", GNAND_InitNAND(&_nandDiskDriver0, ptNDisk, TRUE));
	sysprintf("GNAND mount %x\n", GNAND_MountNandDisk(ptNDisk));
	//sicSdOpen(0);

	sysprintf("    Format disk....\n");
	pDiskList = fsGetFullDiskInfomation();
	fsFormatFlashMemoryCard(pDiskList);
	fsReleaseDiskInformation(pDiskList);
	sysprintf("    Disk format OK\n");
	
	status = create_pattern_file();
	if (status < 0)
	{
		sysprintf("Failed to create pattern file!! (%x)\n", status);
		exit(0);
	}
	
	file_idx = 1;
	
	{
		for (;;)
		{
			status = file_test(file_idx++);
			if (status == ERR_DISK_FULL)
				break;
			
			if (status < 0)
			{
				sysprintf("Test failed, status = %x\n", status);
				exit(0);
			}
		}
		
	}
	sysprintf("Test complete.\n");
	return 0;
}


/*
 * standalone.c - minimal bootstrap for C library
 * Copyright (C) 2000 ARM Limited.
 * All rights reserved.
 */

/*
 * RCS $Revision: 1 $
 * Checkin $Date: 08/08/22 9:02p $ 0
 * Revising $Author: Mncheng $
 */

/*
 * This code defines a run-time environment for the C library.
 * Without this, the C startup code will attempt to use semi-hosting
 * calls to get environment information.
 */
 extern unsigned int Image$$ZI$$Limit;

void _sys_exit(int return_code)
{
label:  goto label; /* endless loop */
}

void _ttywrch(int ch)
{
    char tempch = (char)ch;
    (void)tempch;
}


extern unsigned int Image$$ZI$$Limit;

__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = sysGetSdramSizebyMB()*0x100000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}


/* end of file standalone.c */

/* end of file standalone.c */



